package helmv3

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"sync"

	"minDeploy.com/common"
	"minDeploy.com/models"

	"github.com/spf13/pflag"
	"helm.sh/helm/v3/pkg/action"
	"helm.sh/helm/v3/pkg/chart/loader"
	"helm.sh/helm/v3/pkg/cli"
)

var values = make(map[string]interface{})
var ResChannel = make(chan interface{}, 100)
var Limiter = make(chan bool, 100)
var WG = &sync.WaitGroup{}

func MakeValues(input map[string]interface{}) map[string]interface{} {
	values = map[string]interface{}{
		"global": map[string]interface{}{
			"deployment": map[string]interface{}{
				"metadata": map[string]interface{}{
					"name":        input["name"],
					"namespace":   input["namespace"],
					"annotations": input["dannotations"],
				},
				"spec": map[string]interface{}{
					"replicas":         input["replicas"],
					"imagePullSecrets": input["imagePullSecrets"],
					"imagePullPolicy":  input["imagePullPolicy"],
					"image":            input["image"],
					"command":          input["command"],
					"args":             input["args"],
					"ports":            input["ports"],
					"env":              input["env"],
					"envFrom":          input["envFrom"],
					"resources":        input["resources"],
					"volumes":          input["volumes"],
					"volumeMounts":     input["volumeMounts"],
					"nodeName":         input["nodeName"],
					"nodeSelector":     input["nodeSelector"],
					"affinity":         input["affinity"],
					"startupProbe":     input["startupProbe"],
					"livenessProbe":    input["livenessProbe"],
					"readinessProbe":   input["readinessProbe"],
				},
			},
			"service": map[string]interface{}{
				"ports":       input["servicePorts"],
				"type":        input["serviceType"],
				"annotations": input["sannotations"],
			},
		},
	}
	return values
}

func InstallChart(name string, namespace string, values map[string]interface{}, Limiter chan bool, WG *sync.WaitGroup, processId string) {
	defer WG.Done()
	actionConfig := MakeAction(namespace)
	mychart, err := loader.Load("./chart")
	if err != nil {
		log.Println(err)
	}
	install := action.NewInstall(actionConfig)
	install.Namespace = namespace
	install.ReleaseName = name
	myrelease, err := install.Run(mychart, values)
	if err != nil {
		log.Println(err)
		ResChannel <- fmt.Sprintf("%s", err)
	}

	log.Println("install success release: ", myrelease.Name)
	log.Println(myrelease.Info.Status)
	valstr, _ := json.Marshal(values)
	dh := &models.DeployHistory{Type: "Install", Status: string(myrelease.Info.Status), Info: myrelease.Info.Description, ProcessID: processId, Value: string(valstr), ReleaseName: name, ReleaseNamespace: namespace}
	//ResChannel <- JoinString("Install Chart =============>", myrelease.Name)
	ResChannel <- dh
	<-Limiter
}

func UninstallChart(name string, namespace string, Limiter chan bool, WG *sync.WaitGroup, processId string) {
	defer WG.Done()
	actionConfig := MakeAction(namespace)
	uninstall := action.NewUninstall(actionConfig)
	res, err := uninstall.Run(name)
	if err != nil {
		log.Println(err)
		ResChannel <- fmt.Sprintf("%s", err)
	}
	log.Println(res.Release.Info.Status)
	dh := &models.DeployHistory{Type: "Uninstall", Status: string(res.Release.Info.Status), Info: res.Release.Info.Description, ProcessID: processId, Value: "", ReleaseName: name, ReleaseNamespace: namespace}
	//ResChannel <- JoinString("Uninstall Chart ==========>", res.Release.Name)
	ResChannel <- dh
	<-Limiter
}

func GetValue(name string, namespace string) (map[string]interface{}, error) {
	actionConfig := MakeAction(namespace)
	getvalue := action.NewGetValues(actionConfig)
	resmap, err := getvalue.Run(name)
	return resmap, err

}

func UpgradeChart(name string, namespace string, vals map[string]interface{}, Limiter chan bool, WG *sync.WaitGroup, processId string) {
	defer WG.Done()
	actionConfig := MakeAction(namespace)
	upgrade := action.NewUpgrade(actionConfig)
	nginxChart, err := loader.Load("./chart")
	if err != nil {
		log.Println(err)
	}
	res, _ := upgrade.Run(name, nginxChart, vals)
	log.Println(res.Info.Status)
	log.Println(res.Info.Description)
	if res.Info.Status == "failed" {

		WG.Add(1)
		Limiter <- true
		go RollbackRelease(name, namespace, Limiter, WG)
	}
	valstr, _ := json.Marshal(vals)
	dh := &models.DeployHistory{Type: "Upgrade", Status: string(res.Info.Status), Info: res.Info.Description, ProcessID: processId, Value: string(valstr), ReleaseName: name, ReleaseNamespace: namespace}
	//ResChannel <- JoinString("Upgrade ============> :", res.Name)
	ResChannel <- dh
	<-Limiter

}

func ListRelease(namespace string, Limiter chan bool, WG *sync.WaitGroup, ProcessID string) {
	defer WG.Done()
	actionConfig := MakeAction(namespace)
	list := action.NewList(actionConfig)
	rlist, err := list.Run()
	if err != nil {
		panic(err)
	}
	for _, r := range rlist {
		dh := &models.DeployHistory{Type: "List", Status: string(r.Info.Status), Info: r.Info.Description, ProcessID: ProcessID, ReleaseName: r.Name, ReleaseNamespace: r.Namespace}
		ResChannel <- dh
	}
	<-Limiter

}

func GetRelease(name string, namespace string, Limiter chan bool, WG *sync.WaitGroup, ProcessID string) {
	defer WG.Done()
	actionConfig := MakeAction(namespace)
	myget := action.NewGet(actionConfig)
	rel, err := myget.Run(name)
	if err != nil {
		panic(err)
	}
	dh := &models.DeployHistory{Type: "Get", Status: string(rel.Info.Status), Info: rel.Info.Description, ProcessID: ProcessID, ReleaseName: rel.Name, ReleaseNamespace: rel.Namespace}
	ResChannel <- dh
	<-Limiter

}

func RollbackRelease(name string, namespace string, Limiter chan bool, WG *sync.WaitGroup) {
	defer WG.Done()
	actionConfig := MakeAction(namespace)
	rollback := action.NewRollback(actionConfig)
	err := rollback.Run(name)
	if err != nil {
		panic(err)
	}
	dh := &models.DeployHistory{Type: "Rollback", Status: "", Info: "", Value: "", ProcessID: common.RandomString(25), ReleaseName: name, ReleaseNamespace: namespace}
	ResChannel <- dh
	<-Limiter

}

func MakeAction(namespace string) *action.Configuration {
	settings := cli.New()
	fs := pflag.NewFlagSet("test", pflag.ContinueOnError)
	//fs.StringVarP(&namespace, "aaaa", "t", "testns", "set namespace")
	settings.AddFlags(fs)
	actionConfig := new(action.Configuration)
	if err := actionConfig.Init(settings.RESTClientGetter(), namespace, os.Getenv("HELM_DRIVER"), log.Printf); err != nil {
		log.Println(err)
		os.Exit(1)
	}
	return actionConfig
}
